home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** Program: MacShell
- ** File: AEConnect.c
- ** Written by: Eric Soldan
- **
- ** Copyright © 1990-1991 Apple Computer, Inc.
- ** All rights reserved.
- **
- ** This is the custom AppleEvents code used for establishing a connection
- ** to another window. MacShell targets a specific window in an application,
- ** not just an application. It also sends and returns more information
- ** about the connection, such as user name, zone, and machine. This
- ** information is two-way, so each user can know who they are connected to.
- */
-
-
-
- /*****************************************************************************/
-
-
-
- #include "MacShell.h" /* Get the MacShell includes/typedefs, etc. */
- #include "MacShellCommon.h" /* Get the stuff in common with rez. */
- #include "MacShell.protos" /* Get the prototypes for MacShell. */
-
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
-
- #ifndef THINK_C
- #ifndef __SYSEQU__
- #include <SysEqu.h>
- #endif
- #endif
-
- #ifndef __TOOLUTILS__
- #include <ToolUtils.h>
- #endif
-
- #ifdef THINK_C
- #include "Utilities.h"
- #else
- #ifndef __UTILITIES__
- #include <Utilities.h>
- #endif
- #endif
-
-
-
- /*****************************************************************************/
-
-
-
- extern Boolean gHasAppleEvents;
- extern Cursor *gCursorPtr;
-
- static pascal OSErr DoAEAnswer(AppleEvent *message, AppleEvent *reply, long refcon);
- static pascal OSErr ReceiveConnect(AppleEvent *message, AppleEvent *reply, long refcon);
- static pascal OSErr ReceiveConnectReply(AppleEvent *message, AppleEvent *reply);
- static pascal Boolean AEPortFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo);
-
-
-
- /*****************************************************************************/
-
-
-
- static triplets keywordsToInstall[] = {
- { kCoreEventClass, kAEAnswer, (ProcPtr)DoAEAnswer },
- { kCustomEventClass, keyAppConnect, (ProcPtr)ReceiveConnect },
- }; /* These are the custom AppleEvents. */
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- /* InitConnectAppleEvents
- **
- ** Install the AppleEvents we use to establish a connection to a specific
- ** window. This is done in addition to installing the required AppleEvents.
- ** InitAppleEvents, which installs the required AppleEvents, must be called
- ** first, since it sets up some global values.
- */
-
- #pragma segment AppleEvents
- void InitConnectAppleEvents(void)
- {
- OSErr err;
- short i;
-
- if (gHasAppleEvents) {
- for (i = 0; i < (sizeof(keywordsToInstall) / sizeof(triplets)); ++i) {
- err = AEInstallEventHandler(
- keywordsToInstall[i].theEventClass, /* What class to install. */
- keywordsToInstall[i].theEventID, /* Keywords to install. */
- keywordsToInstall[i].theHandler, /* The AppleEvent handler. */
- 0L, /* Unused refcon. */
- false /* Only for our app. */
- );
-
- if (err) {
- Alert(rErrorAlert, (ModalFilterProcPtr)alertFilter);
- return;
- }
- }
- }
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #pragma segment AppleEvents
- pascal OSErr DoAEAnswer(AppleEvent *message, AppleEvent *reply, long refcon)
- {
- #pragma unused (refcon)
-
- OSErr err;
-
- gCursorPtr = nil;
- /* Force re-calc of cursor region and cursor to use. */
-
- err = ReceiveConnectReply(message, reply);
-
- AEPutParamPtr( /* RETURN REPLY ERROR, EVEN IF NONE... */
- reply, /* The AppleEvent. */
- keyReplyErr, /* AEKeyword */
- typeShortInteger, /* Desired type. */
- (Ptr)&err, /* Pointer to area for data. */
- sizeof(short) /* Size of data area. */
- );
-
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* SendConnect
- **
- */
-
- #pragma segment AppleEvents
- OSErr SendConnect(FileRecHndl frHndl)
- {
- AEAddressDesc remoteLoc;
- OSErr err;
- long windID[2], size;
- char hstate;
- Ptr ptr1, ptr2;
- AppleEvent theAevt, reply;
- Str255 macText, appText;
- Str32 remoteName;
- Handle remoteNameHndl;
- FSSpec myFSS;
- short i;
-
- theAevt.dataHandle = reply.dataHandle = nil;
- /* Make sure disposing of the descriptors is okay in all cases.
- ** This will not be necessary after 7.0b3, since the calls that
- ** attempt to create the descriptors will nil automatically
- ** upon failure. */
-
- err = noErr;
- /* We may not make the first operation that can cause an error,
- ** so we have to initialize err. */
-
- remoteLoc.dataHandle = nil;
- /* Make it safe to dispose of in all cases. */
-
- GetIndString(macText, rPPCText, sTitleText);
- GetIndString(appText, rPPCText, sAppText);
- err = MakeTarget(&remoteLoc, false, kAEWaitReply,
- macText, appText, (PPCFilterProcPtr)AEPortFilter, (char *)"\pMacShell");
- /* Generate the target for the remote user. */
- (*frHndl)->connect.windowID[0] = windID[0] = (TickCount() & 0xFFFFFFFE);
- (*frHndl)->connect.windowID[1] = windID[0];
- (*frHndl)->connect.remoteLoc = remoteLoc;
-
- if (!err) { /* Create the AppleEvent... */
- err = AECreateAppleEvent( /* CREATE EMPTY APPLEEVENT. */
- kCustomEventClass, /* Event class. */
- typeAppConnect, /* Event ID. */
- &remoteLoc, /* Address of receiving app. */
- kAutoGenerateReturnID, /* This value causes the */
- /* AppleEvent manager to */
- /* assign a return ID that */
- /* is unique to the session. */
- kAnyTransactionID, /* Ignore transaction ID. */
- &theAevt /* Location of event. */
- );
- }
-
- if (!err) { /* If we have an empty list to add to... */
- hstate = LockHandleHigh((Handle)frHndl);
- ptr1 = (Ptr)&((*frHndl)->connect);
- ptr2 = (Ptr)&((*frHndl)->connect.endSendInfo);
- size = (long)ptr2 - (long)ptr1;
- err = AEPutParamPtr( /* ADD FILE INFO TO THE APPLEEVENT. */
- &theAevt, /* AppleEvent to add to. */
- keyAppConnect, /* AEKeyword. */
- typeAppConnect, /* Desired type. */
- ptr1, /* Pointer to the data to be sent. */
- size /* Size of the data to be sent. */
- );
- HSetState((Handle)frHndl, hstate);
- }
-
- if (!err) {
- myFSS = (*frHndl)->fileState.fss;
- err = AEPutParamPtr( /* ADD WINDOW NAME TO APPLEEVENT. */
- &theAevt, /* AppleEvent to add to. */
- keyFSS, /* AEKeyword. */
- typeFSS, /* Desired type. */
- (Ptr)&myFSS, /* Pointer to the data. */
- sizeof(FSSpec) /* Size of the data. */
- );
- }
-
- if (!err) {
- remoteName[0] = 0;
- if (remoteNameHndl = GetResource('STR ', -16096))
- pstrcpy((char *)remoteName, (char *)(*remoteNameHndl));
- err = AEPutParamPtr( /* ADD USER NAME TO APPLEEVENT. */
- &theAevt, /* AppleEvent to add to. */
- keyPascal, /* AEKeyword. */
- typePascal, /* Desired type. */
- (Ptr)remoteName, /* Pointer to the data. */
- remoteName[0] + 1 /* Size of the data. */
- );
- }
-
- if (!err) { /* If we have an AppleEvent ready to send... */
- err = AESend( /* SEND APPLEEVENT. */
- &theAevt, /* Our Apple Event to send. */
- &reply, /* We may have a reply. */
- kAEQueueReply, /* Type of reply. */
- kAENormalPriority, /* App. send priority. */
- 0, /* We aren't waiting. */
- nil, /* We aren't waiting. */
- nil /* EventFilterProcPtr. */
- );
- }
- if (remoteLoc.descriptorType == typeProcessSerialNumber)
- err = ReceiveConnectReply(&reply, &reply);
- /* If we want a queue reply, and if we are sending to ourselves,
- ** then we already have the reply. Since we are sending to
- ** ourselves, we don't have to wait for an event. Stuff happens
- ** right away. We're (probably) happy. */
-
- AEDisposeDesc(&theAevt);
- AEDisposeDesc(&reply);
- /* Dispose of the descriptors, created or not.
- ** If not created, no harm done by calling. */
-
- if (err) {
- AEDisposeDesc(&remoteLoc);
- /* If we didn't connect, get rid of the target descriptor. */
-
- for (i = 0; i < 2; ++i) (*frHndl)->connect.windowID[i] = 0;
- /* Mark this window so that it will never be found if we somehow
- ** do get an answer from the receiver, even after failure. */
- }
-
- return(err);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* ReceiveConnect
- **
- */
-
- #pragma segment AppleEvents
- pascal OSErr ReceiveConnect(AppleEvent *message, AppleEvent *reply, long refcon)
- {
- #pragma unused (refcon)
-
- OSErr err;
- FileRecHndl frHndl;
- char hstate;
- Ptr ptr1, ptr2;
- long size, windID[2];
- AEAddressDesc senderTarget;
- DescType ignoredType;
- Size ignoredSize;
- FSSpec myFSS;
- Str32 remoteZone, remoteMachine, remoteApplication;
- char remoteName[33];
- Handle remoteNameHndl;
-
- err = noErr;
- AEPutParamPtr( /* RETURN REPLY ERROR, EVEN IF NONE... */
- reply, /* The AppleEvent. */
- keyReplyErr, /* AEKeyword */
- typeShortInteger, /* Desired type. */
- (Ptr)&err, /* Pointer to area for data. */
- sizeof(short) /* Size of data area. */
- );
-
- IncNewFileNum(false);
- err = AppNewDocument(&frHndl, docFileType);
- IncNewFileNum(true);
-
- if (err) return(err);
-
- if (!err) {
- hstate = LockHandleHigh((Handle)frHndl);
- ptr1 = (Ptr)&((*frHndl)->connect);
- ptr2 = (Ptr)&((*frHndl)->connect.endSendInfo);
- size = (long)ptr2 - (long)ptr1;
- err = AEGetParamPtr( /* GET CONNECT INFO FROM THE APPLEEVENT. */
- message, /* The AppleEvent. */
- keyAppConnect, /* AEKeyword */
- typeAppConnect, /* Desired type. */
- &ignoredType, /* Type code. */
- ptr1, /* Pointer to area for data. */
- size, /* Size of data area. */
- &ignoredSize /* Returned size of data. */
- );
- HSetState((Handle)frHndl, hstate);
- }
-
- if (!err) {
- err = AEGetAttributeDesc( /* GET ADDRESS OF SENDER. */
- message, /* Get address of sender from message. */
- keyAddressAttr, /* We want an address. */
- typeWildCard, /* We want the address of the sender. */
- &senderTarget /* Address of sender. */
- );
- if (!err) {
- (*frHndl)->connect.remoteLoc = senderTarget;
- err = AEGetParamPtr( /* GET FSSpec (FOR WINDOW NAME) FROM APPLEEVENT. */
- message, /* The AppleEvent. */
- keyFSS, /* AEKeyword */
- typeFSS, /* Desired type. */
- &ignoredType, /* Type code. */
- (Ptr)&myFSS, /* Pointer to area for data. */
- sizeof(FSSpec), /* Size of the data. */
- &ignoredSize /* Returned size of data. */
- );
- if (!err)
- pstrcpy((char *)(*frHndl)->fileState.fss.name, (char *)myFSS.name);
- }
- if (!err) {
- err = AEGetParamPtr( /* GET USER NAME FROM APPLEEVENT. */
- message, /* The AppleEvent. */
- keyPascal, /* AEKeyword */
- typePascal, /* Desired type. */
- &ignoredType, /* Type code. */
- remoteName, /* Pointer to area for data. */
- sizeof(Str255), /* Size of the data. */
- &ignoredSize /* Returned size of data. */
- );
- (*frHndl)->connect.remoteName[0] = 0;
- if (!err) {
- pstrcpy((char *)(*frHndl)->connect.remoteName, (char *)remoteName);
- remoteZone[0] = remoteMachine[0] = 0;
- GetTargetInfo(senderTarget, remoteZone, remoteMachine, remoteApplication);
- pstrcpy((char *)&(*frHndl)->connect.remoteZone[0], (char *)remoteZone);
- pstrcpy((char *)&(*frHndl)->connect.remoteMachine[0], (char *)remoteMachine);
- }
- }
- }
-
- if (!err) { /* If we got the remote user address... */
-
- (*frHndl)->connect.windowID[0] = windID[0] = (TickCount() | 0x01);
- (*frHndl)->connect.connected = true;
-
- if ((*frHndl)->doc.version != kVersion) err = errAEWrongDataType;
- /* Incompatible file format. */
-
- if (!err) {
- windID[1] = (*frHndl)->connect.windowID[1];
- err = AEPutParamPtr( /* RETURN RECEIVER WINDOW ID. */
- reply, /* The AppleEvent. */
- keyWindowID, /* AEKeyword */
- typeDoubleLong, /* Type code. */
- (Ptr)&windID[0], /* Pointer to area for data. */
- 2 * sizeof(long) /* Size of data area. */
- );
- }
-
- if (!err) {
- remoteName[0] = 0;
- if (remoteNameHndl = GetResource('STR ', -16096))
- pstrcpy((char *)remoteName, (char *)(*remoteNameHndl));
- err = AEPutParamPtr( /* RETURN RECEIVER USER NAME. */
- reply, /* The AppleEvent. */
- keyPascal, /* AEKeyword */
- typePascal, /* Type code. */
- remoteName, /* Pointer to area for data. */
- remoteName[0] + 1 /* Size of data area. */
- );
- }
-
- if (!err) err = DoNewWindow(frHndl, nil, (WindowPtr)-1, kwAppWindow);
- /* If connecting worked, create a window for the document. */
- }
-
- if (err) AppDisposeDocument(frHndl);
-
- if (!err) NotifyUser();
- return(err);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #pragma segment AppleEvents
- pascal OSErr ReceiveConnectReply(AppleEvent *message, AppleEvent *reply)
- {
- #pragma unused (reply)
-
- OSErr err, replyErr;
- DescType actualType;
- long windID[2], actualSize;
- WindowPtr window;
- FileRecHndl frHndl;
- Str32 remoteZone, remoteMachine, remoteApplication;
- char remoteName[33];
-
- err = AEGetParamPtr( /* CHECK FOR A RECEIVER ERROR... */
- message, /* The AppleEvent. */
- keyReplyErr, /* AEKeyword */
- typeShortInteger, /* Desired type. */
- &actualType, /* Type code. */
- (Ptr)&replyErr, /* Pointer to area for data. */
- sizeof(short), /* Size of data area. */
- &actualSize /* Returned size of data. */
- );
- if (!err) err = replyErr;
-
- if (!err) {
- err = AEGetParamPtr( /* GET RECEIVER WINDOW ID. */
- message, /* The AppleEvent. */
- keyWindowID, /* AEKeyword */
- typeDoubleLong, /* Desired type. */
- &actualType, /* Type code. */
- (Ptr)&windID[0], /* Pointer to area for data. */
- 2 * sizeof(long), /* Size of data area. */
- &actualSize /* Returned size of data. */
- );
- }
-
- if (!err) { /* If we got the receiver window ID... */
-
- window = GetAEWindow(windID[1], windID[1]);
- /* The ID's are still both ours, since this is where we
- ** get the receiver's ID returned. windID[0] holds the
- ** receiver's ID, and windID[1] holds ours. */
-
- if (window) {
- frHndl = (FileRecHndl)GetWRefCon(window);
- if (!(*frHndl)->connect.connected) {
- err = AEGetParamPtr(
- message, /* The AppleEvent. */
- keyPascal, /* AEKeyword */
- typePascal, /* Desired type. */
- &actualType, /* Type code. */
- remoteName, /* Pointer to area for data. */
- sizeof(Str255), /* Size of data area. */
- &actualSize /* Returned size of data. */
- );
-
- (*frHndl)->connect.remoteName[0] = 0;
- if (!err) {
- (*frHndl)->connect.windowID[1] = windID[0];
- pstrcpy((char *)&(*frHndl)->connect.remoteName[0], (char *)remoteName);
- GetTargetInfo((*frHndl)->connect.remoteLoc,
- remoteZone, remoteMachine, remoteApplication);
- pstrcpy((char *)&(*frHndl)->connect.remoteZone[0], (char *)remoteZone);
- pstrcpy((char *)&(*frHndl)->connect.remoteMachine[0], (char *)remoteMachine);
- (*frHndl)->connect.connected = true;
- }
- else
- (*frHndl)->connect.windowID[0] = (*frHndl)->connect.windowID[1] = 0;
- }
- }
- }
-
- return(err);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* GetAEWindow
- **
- ** Find the window with the specified window ID's.
- */
-
- #pragma segment AppleEvents
- WindowPtr GetAEWindow(long windID_0, long windID_1)
- {
- WindowPeek window;
- FileRecHndl frHndl;
-
- #ifdef __SYSEQU__
- for (window = *(WindowPeek *)WindowList; window; window = window->nextWindow) {
- #else
- for (window = (WindowPeek)WindowList; window; window = window->nextWindow) {
- #endif
- if (IsAppWindow((WindowPtr)window)) {
- frHndl = (FileRecHndl)GetWRefCon((WindowPtr)window);
- if (
- ((*frHndl)->connect.windowID[0] == windID_0) &&
- ((*frHndl)->connect.windowID[1] == windID_1)
- ) return((WindowPtr)window);
- }
- }
-
- return(nil);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* AEPortFilter
- **
- ** Don't allow PPCBrowser to show any applications other than MacShell.
- */
-
- #pragma segment AppleEvents
- pascal Boolean AEPortFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
- {
- #pragma unused (locationName)
-
- long type;
-
- if (thePortInfo->name.portKindSelector == ppcByString) {
- BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
- /* The BlockMove is so that we don't get an address error
- ** on a 68000-based machine due to referencing a long at
- ** an odd-address. */
- if (type == docCreator) return(true);
- }
-
- return(false);
- }
-
-
-
-